//
//  referenceVariables.cpp
//  learnC++
//
//  Created by apple on 2018/5/30.
//  Copyright © 2018年 yunfan.com. All rights reserved.
//

#include "referenceVariables.hpp"

using namespace std;

static void changeN(int &ref){
    ref = 6;
}

static void printElements(int (&arr)[4]){
    int length{sizeof(arr)/sizeof(arr[0])};
    
    for (int i{0}; i < length; ++i) {
        cout << arr[i] << endl;
    }
    
    //引用返回最好加out后缀
    arr[1] += 1;
    int arr1Out = arr[1];
    
}


static void test_const_reference(){
    const int value = 5;
    const int &ref = value;

    cout << value << " = " << ref << "\n";
    
}

//测试reference的r值问题
int returnByValue()
{
    return 5;
}

const int& returnByValue2()
{
    return 5;//返回后变量被销毁，很危险
}

int& returnByReference()
{
    static int x = 5; // static ensures x isn't destroyed when it goes out of scope
    return x;
}

//为避免产生不必要的潜在的昂贵的副本，不是指针或基本数据类型（int，double等等）的变量应该通常由（const）引用传递。基本数据类型应该按值传递，除非函数需要改变它们。


//通过结构或类时（使用通过引用）。
//传递基本类型时（使用按值传递）。
//正如你所看到的，通过地址和通过引用具有几乎相同的优点和缺点。由于通过引用通常比通过地址更安全，因此在大多数情况下应优先通过引用。

//引用通常由编译器实现为指针
void test_reference_variable(){
    
    int value = 5;
    
    testreferaceParam(value);
    
//    一个引用作为被引用对象的别名。引用不能更改指向
    int &ref = value;//reference引用
    
    value = 6;
    ref = 7;
    
    cout << value << "\n";
    ++ref;
    cout << value << "\n";
    
    changeN(value);
    
    cout << value << "\n";
    
    //引用数组
    int arr[]{99,20,12,34};
    
    printElements(arr);
    
    Other other{{0,0},0};
    int &ref2 = other.something.value1;
    
    ref2 = 5;
    
    cout << other.something.value1 << "\n";
    
    test_const_reference();
    
    Other other2{{0,0},0};
    Other *ptr3 = &other2;
    ptr3->something.value1 = 10;
    
    int &value3 = returnByReference(); // case A -- ok, treated as return by value
//    int &ref3 = returnByValue(); // case B -- compile error since the value is an r-value, and an r-value can't bind to a non-const reference
    
    value3 = 4;
    
    cout << value3 << endl;
    
    int &value6 = returnByReference();
    
    cout << value6 << endl;
    
    //当reference赋值为r值时，即常量如5，2+3等，不能修改它的值，所以需要加const
    const int &cref3 = returnByValue2();
    
}

void testreferaceParam(int & a){
    
    cout << a << "LLL";
    
}

